package com.zn.bestSignClient;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.zn.entity.AppAgreement;
import com.zn.entity.AppCustomer;
import com.zn.entity.CustomerAgreement;
import com.zn.mapper.AppAgreementMapper;
import com.zn.mapper.CustomerAgreementMapper;
import com.zn.service.AppCustomerService;
import com.zn.util.*;
import com.zn.vo.Message;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by admintrator on 2019/2/26.
 */
@Component
public class BestSignService {

    private static final Logger logger = LoggerFactory.getLogger(BestSignService.class);

    @Autowired
    private AppCustomerService appCustomerService;
    @Autowired
    private AppAgreementMapper appAgreementMapper;
    @Autowired
    private CustomerAgreementMapper customerAgreementMapper;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Value("${bestsign.path.url}")
    private String shangshangqianUrl;
    @Value("${bestsign.path.developerId}")
    private String developerId;
    @Value("${bestsign.path.account}")
    private String account;
    @Value("${bestsign.path.privateKey}")
    private String privateKey;
    @Value("${bestsign.path.accessKey}")
    private String accessKey;
    @Value("${bestsign.path.templateNum}")
    private String templateNum;
    @Value("${bestsign.path.getTemplateVars}")
    private String getTemplateVars;
    @Value("${bestsign.path.createContractPdf}")
    private String createContractPdf;
    @Value("${bestsign.path.createByTemplate}")
    private String createByTemplate;
    @Value("${bestsign.path.template}")
    private String signTemplate;
    @Value("${bestsign.path.getTemplate}")
    private String getTemplate;
    @Value("${bestsign.path.sendByTemplate}")
    private String sendByTemplate;
    @Value("${bestsign.path.userReg}")
    private String userReg;
    @Value("${bestsign.path.applyCertStatus}")
    private String findapplyCertStatus;
    @Value("${bestsign.path.contractDownload}")
    private String contractDownload;
    @Value("${bestsign.path.getPreviewURL}")
    private String getPreviewURL;
    @Value("${oss.end.point}")
    private  String endPoint;
    @Value("${oss.access.key.id}")
    private  String ossAccessKeyId;
    @Value("${oss.access.key.secret}")
    private  String ossAccessKeySecret;
    @Value("${oss.bucket.name}")
    private  String bucketName;
    @Value("${oss.url}")
    private  String ossUrl;

    private static String urlSignParams = "?developerId=%s&rtick=%s&signType=rsa&sign=%s";

    /**
     * 客户注册上上签
     * @param record
     * @return
     */
    public int sendUserReg(AppCustomer record){
        JSONObject requestBody = new JSONObject();
        requestBody.put("account",record.getCustomerId());
        requestBody.put("name", record.getName());
        requestBody.put("userType", "1");
        JSONObject json = new JSONObject();
        json.put("identity",record.getIdCard());
        requestBody.put("credential",json);
        requestBody.put("applyCert","1");
        /**个人用户注册上上签**/
        String userReponse = getPostUrlParams(developerId, privateKey, shangshangqianUrl, userReg, requestBody.toJSONString());
        if (StringUtils.isNotBlank(userReponse)) {
            record.setSsqStatus(1);
            return appCustomerService.updateSsqContractId(record);
        }else {
            return 0;
        }
    }


    /**
     * 根据模板生成并获取返回合同
     * @return  签约长短连接地址
     */
    public String getTemplateVars(AppCustomer record){
        JSONObject requestBody = new JSONObject();
        requestBody.put("tid",templateNum);
        requestBody.put("isRetrieveAllVars", "1");
        /**获取合约模板**/
        String templateVars = getPostUrlParams(developerId, privateKey, shangshangqianUrl, getTemplateVars, requestBody.toJSONString());
        if (StringUtils.isBlank(templateVars)){return null;}
        /**模版生成合同文件**/
        requestBody = new JSONObject();
        requestBody.put("account",account);
        requestBody.put("tid",templateNum);
        JSONObject templateValues = new JSONObject();
        templateValues.put("customerName",record.getName()+"("+record.getIdCard()+")");
        requestBody.put("templateValues",templateValues);
        requestBody.put("groupValues","");
        String contractPdf = getPostUrlParams(developerId, privateKey, shangshangqianUrl, createContractPdf, requestBody.toJSONString());
        if (StringUtils.isBlank(contractPdf)){return null;}
        /**模版创建合同 **/
        requestBody = new JSONObject();
        requestBody.put("account",account);
        requestBody.put("tid",templateNum);
        JSONObject jsonObject = JSON.parseObject(contractPdf);
        requestBody.put("templateToken",jsonObject.getString("templateToken"));
        requestBody.put("title","合同");
        requestBody.put("expireTime", String.valueOf(DateUtils.addHour(new Date(), 2).getTime()/1000));
        String createTemplate = getPostUrlParams(developerId, privateKey, shangshangqianUrl, createByTemplate, requestBody.toJSONString());
        if (StringUtils.isBlank(createTemplate)){return null;}
        /**模版变量签署合同  **/
        requestBody = new JSONObject();
        jsonObject = JSON.parseObject(createTemplate);
        String contractId = jsonObject.getString("contractId");
        requestBody.put("contractId",contractId);
        requestBody.put("tid",templateNum);
        jsonObject = new JSONObject();
        JSONObject json = new JSONObject();
        jsonObject.put("account", account);
        json.put("createDate",jsonObject);
        json.put("date",jsonObject);
        requestBody.put("vars",json);
        requestBody.put("signIp","");
        requestBody.put("loginIp","");
        String accountSignTemplate = getPostUrlParams(developerId, privateKey, shangshangqianUrl, signTemplate, requestBody.toJSONString());
        if (StringUtils.isBlank(accountSignTemplate)){return null;}
        /**获取模版信息  **/
        requestBody = new JSONObject();
        requestBody.put("tid",templateNum);
        String accountTemplate = getPostUrlParams(developerId, privateKey, shangshangqianUrl, getTemplate, requestBody.toJSONString());
        if (StringUtils.isBlank(accountTemplate)){return null;}
        /**用模版变量的手动签   **/
        requestBody = new JSONObject();
        requestBody.put("contractId",contractId);
        requestBody.put("expireTime","0");
        requestBody.put("dpi","160");
        requestBody.put("signer",record.getCustomerId());
        requestBody.put("tid",templateNum);
        requestBody.put("varNames","sign");
        requestBody.put("isAllowChangeSignaturePosition","0");
        requestBody.put("returnUrl","");
        requestBody.put("vcodeMobile",record.getCustomerTel());
        requestBody.put("isDrawSignatureImage","1");
        requestBody.put("signatureImageName","");
        requestBody.put("pushUrl","");
        String accountSendByTemplate = getPostUrlParams(developerId, privateKey, shangshangqianUrl, sendByTemplate, requestBody.toJSONString());
        return accountSendByTemplate;
    }

    /**
     * 拼接请求地址
     * @param openId  开发者ID
     * @param key     私钥
     * @param url     请求地址
     * @param actionUrl  请求方法
     * @param parameters  请求参数
     * @return
     */
    public String getPostUrlParams(String openId, String key, String url, String actionUrl, String parameters){
        // 生成一个时间戳参数
        String rtick = RSAUtils.getRtick();
        // 计算参数签名
        String paramsSign = RSAUtils.calcRsaSign(openId,
                key, url, actionUrl, rtick, null, parameters);
        // 签名参数追加为url参数
        String urlParams = String.format(urlSignParams, openId,
                rtick, paramsSign);
        // 发送请求
        try {
            logger.info("getPostUrlParams................SsqUrl........"+url+"action........."+actionUrl+"urlParams......"+urlParams+"parameters...."+parameters);
            String responseBody = HttpClientSender.sendHttpPost(url, actionUrl, urlParams, parameters);
            JSONObject templateJson = JSON.parseObject(responseBody);
            if (templateJson.getInteger("errno") == 0){
                responseBody = templateJson.getString("data");
                return responseBody;
            }else {
                logger.info("getPostUrlParams.............."+templateJson.toString());
                return null;
            }
        }catch (Exception ex){
            logger.error(ex.getMessage());
            logger.error("getPostUrlParams..........."+parameters);
            return null;
        }
    }

    /**
     * 同步请求
     * @param openId
     * @param key
     * @param url
     * @param actionUrl
     * @param map
     * @return
     */
    public byte[] getUrlParams(String openId, String key, String url, String actionUrl, Map<String, Object> map){
        // 生成一个时间戳参数
        String rtick = RSAUtils.getRtick();
        String urlParams = "";
        for (String str : map.keySet()){
            urlParams += str +"="+map.get(str);
        }
        // 计算参数签名
        String paramsSign = RSAUtils.calcRsaSign(openId,
                key, url, actionUrl, rtick, urlParams, null );
        // 签名参数追加为url参数
        urlParams = String.format(urlSignParams, openId,
                rtick, paramsSign)+"&"+urlParams;
        // 发送请求
        try {
            logger.info("getUrlParams................SsqUrl........"+url+"action........."+actionUrl+"urlParams......"+urlParams+"parameters...."+map.toString());
            byte[] responseBody = HttpClientSender.sendHttpGet(url, actionUrl,
                    urlParams);
            return responseBody;
        }catch (Exception ex){
            logger.error(ex.getMessage());
            logger.error("getUrlParams..........."+map.toString());
            return null;
        }
    }

    /**
     * 接收处理返回参数
     * @param ssqPostParams
     * @return
     */
    @Transactional
    public int postUrlParams(String ssqPostParams, HttpServletRequest request){
        int count = 0;
        String rtick = request.getHeader("rtick");
        String sign = request.getHeader("sign");
        logger.info("postUrlParams........rtick="+rtick+"sign="+sign+"params="+ssqPostParams);
        //双MD5加密验签
        String checkSign = EnDecryptUtil.MD5(EnDecryptUtil.MD5(ssqPostParams)+rtick+accessKey);
        if (!checkSign.equals(sign)){
            count = -1;
            return count;
        }
        JSONObject jsonObject = JSON.parseObject(ssqPostParams);
        JSONObject json = JSONObject.parseObject(jsonObject.getString("params"));
        AppCustomer record = new AppCustomer();
        record.setCustomerId(json.getString("account"));
        AppCustomer appCustomer = appCustomerService.selectByPrimaryKey(record.getCustomerId());
        if (json.containsKey("status")){//判断为个人用户开户返回
            JSONObject redisJson = new JSONObject();
            redisJson.put("customerId", record.getCustomerId());
            if ("5".equals(json.getString("status")) && appCustomer.getSsqStatus() != 2) {
                record.setSsqStatus(2);
                count = appCustomerService.updateSsqContractId(record);
                if (count > 0){
                    redisJson.put("status", 0);
                }
            }else {
                redisJson.put("status", 1);
                logger.error("postUrlParams........."+json.getString("message"));
            }
            logger.info(redisJson.toString());
            redisTemplate.convertAndSend(Constant.BESTSIGN_ASYNCHRONOUS_NOTIFICATION, redisJson.toString());
        }else if (json.containsKey("signerStatus")){//判断为个人手签成功返回
            if ("2".equals(json.getString("signerStatus")) && StringUtils.isBlank(appCustomer.getSsqContractId())){
                record.setSsqContractId(json.getString("contractId"));
                record.setSsqStatus(4);
                count = appCustomerService.updateSsqContractId(record);
                /**异步上传文件加上图片**/
                OSSuplodPath(json);
            }else {
                logger.error("postUrlParams........."+json.getString("errMsg"));
            }
        }else {
            logger.error("当前类型暂不处理");
            count = 1;
        }
        return count;
    }

    /**
     * 处理OSS上传签约成功合同和合同图片处理上传
     * @param json
     */
    public void OSSuplodPath(JSONObject json){
        Map<String, Object> map = new HashMap<>();
        map.put("contractId",json.getString("contractId"));
        try {
            byte[] bytes = getUrlParams(developerId, privateKey, shangshangqianUrl, contractDownload, map);
            OSSUtil ossUtil=OSSUtil.getInstance(endPoint,ossAccessKeyId,ossAccessKeySecret,bucketName,ossUrl);
            OSSClient ossClient = ossUtil.getOSSClient();
            String fileName = json.getString("account")+"-"+new Date().getTime()+".pdf";
            String diskName = "BestSign/"+DateUtils.formatDate(new Date());
            boolean uploadFlag = ossUtil.uploadInputStreamObject2OSS(ossClient, new ByteArrayInputStream(bytes), fileName , diskName);
            String fileUrl = ossUrl+"/"+diskName+"/"+fileName;
            if (uploadFlag){
                String imageType = "jpg";
                InputStream inputStream = PdfToImageUtil.pdf2multiImage(PdfToImageUtil.getInputStreamByUrl(fileUrl), imageType);
                String fileImageName = json.getString("account")+"-image-"+new Date().getTime()+"."+imageType;
                ossUtil.uploadInputStreamObject2OSS(ossClient, inputStream, fileImageName , diskName);
                fileUrl = ossUrl+"/"+diskName+"/"+fileImageName;

                /**保存用户协议地址**/
                AppAgreement appAgreement = new AppAgreement();
                appAgreement.setAgreementCode("riskAgreement");
                appAgreement.setAgreementStatus(0);
                List<AppAgreement> appAgreementList = appAgreementMapper.selectBySelective(appAgreement);
                if (appAgreementList!=null && appAgreementList.size() > 0){
                    appAgreement = appAgreementList.get(0);
                    CustomerAgreement customerAgreement = new CustomerAgreement();
                    customerAgreement.setCustomerAgreementId(UUIDUtils.getUuid());
                    customerAgreement.setAgreementId(appAgreement.getAgreementId());
                    customerAgreement.setCustomerAgreementPic(fileUrl);
                    customerAgreement.setCustomerId(json.getString("account"));
                    customerAgreement.setEffectiveStatus(0);
                    customerAgreement.setEffectiveDate(DateUtils.getDate(new Date()));
                    customerAgreementMapper.insert(customerAgreement);
                }
            }
        }catch (Exception ex){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.error("OSSuplodPath........."+ex.getMessage());
        }
    }

    /**
     * 校验是否需要签署上上签协议
     * @param record
     * @return
     */
    public Message checkCustomerSsqStatus(AppCustomer record){
        AppAgreement appAgreement = new AppAgreement();
        appAgreement.setAgreementCode("riskAgreement");
        appAgreement.setAgreementStatus(0);
        List<AppAgreement> appAgreementList = appAgreementMapper.selectBySelective(appAgreement);
        if (appAgreementList!=null && appAgreementList.size() > 0){//判断是否需要签署上上签
            record = appCustomerService.selectByPrimaryKey(record.getCustomerId());
            logger.error(record.toString());
            if (StringUtils.isNotBlank(record.getSsqStatus().toString())){
                switch (record.getSsqStatus()){
                    case 0://未在上上签开户
                        return Message.BESTSIGN_CUSTOMER_UNREGISTERED;
                    case 1://开户申请中
                        return Message.BESTSIGN_CUSTOMER_APPLICATION;
                    case 2://开户成功未签署协议
                         return Message.BESTSIGN_CUSTOMER_NOT_SIGNED;
                    case 3://开户失败
                        return Message.BESTSIGN_CUSTOMER_FAIL;
                    case 4:
                        if (StringUtils.isNotBlank(record.getSsqContractId())){//判断是否签署协议
                            return Message.BESTSIGN_CUSTOMER_SUCCESS;
                        }
                    default://异常参数，暂时不处理
                        return Message.BESTSIGN_CUSTOMER_PARAMETER_EXCEPTION;
                }
            }else {//未提交申请
                return Message.BESTSIGN_CUSTOMER_UNREGISTERED;
            }
        }else {//平台方未开始协议签署功能
            return Message.BESTSIGN_CUSTOMER_NOT_OPENED;
        }
    }
}